package com.visec.hdy.sync.ftp.code;

import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorCompletionService;

import org.apache.commons.net.ftp.FTP;

import com.visec.hdy.sync.ftp.config.FtpSendClient;
import com.visec.hdy.sync.ftp.config.SyncConfig;
import com.visec.hdy.sync.ftp.config.SyncFile;
import com.visec.hdy.sync.ftp.config.SyncFileMsg;
import com.visec.hdy.sync.ftp.config.TransmissionAction;
import com.visec.hdy.transmission.ftp.code.FtpClientInter;
import com.visec.hdy.transmission.socket.code.SocketClient;

public class FtpTransmissionImp implements Transmission {
	private ThreadLocal<SyncConfig> threadLocal;

	protected FtpTransmissionImp() {
		// TODO Auto-generated constructor stub
	}

	public static Transmission getInstance(ThreadLocal<SyncConfig> t) {
		FtpTransmissionImp ft = new FtpTransmissionImp();
		ft.threadLocal = t;
		return ft;
	}

	protected SyncConfig getFtpConfig() {
		if (threadLocal.get() == null)
			try {
				throw new Exception("threadlocal no have ftpclient");
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		return threadLocal.get();
	}

	class FtpSyncCallable implements Callable<SyncFile> {
		private FtpSendClientTool ftpSendClientTool;
		private SyncFileMsg ffm;
		private int defaultSize;
		private TransmissionAction action;
		private boolean isSave;
		private FtpSendClient ftpSendClient;

		public FtpSyncCallable(FtpSendClientTool ftpSendClientTool, FtpSendClient ftpSendClient, SyncFileMsg ffm,
				int defaultSize, TransmissionAction action, boolean isSave) {
			super();
			this.ftpSendClientTool = ftpSendClientTool;
			this.ffm = ffm;
			this.defaultSize = defaultSize;
			this.action = action;
			this.isSave = isSave;
			this.ftpSendClient = ftpSendClient;
		}

		@Override
		public SyncFile call() throws Exception {
			// TODO Auto-generated method stub
			FtpClientInter fc = ftpSendClient.getFtpClientInter();
			SocketClient sc = ftpSendClient.getSocketClient();
			if (sc == null) {
				return new SyncFile(ffm, "false");
			}
			if (!(sc.isConnected())) {
				try {
					sc.connect();
				} catch (Exception e) {
					// TODO: handle exception
					return new SyncFile(ffm, "false");
				}
			}
			try {
				if (fc.login()) {
					try {
						Runtime.getRuntime()
								.exec("logger -p local5.info ftp-client-send-file=ftpId:" + ffm.getFtpId()
										+ ",file dir:" + ffm.getFtpFileModel().getDir() + ",file name:"
										+ ffm.getFtpFileModel().getFileName() + ",file size:"
										+ ffm.getFtpFileModel().getFileSize());
					} catch (Exception e1) {
						// TODO: handle exception

					}
					ffm.setPrefix(action);
					sc.write(ffm.toString());
					try {
						fc.entryDir(ffm.getFtpFileModel().getDir());
					} catch (Exception e) {
						// TODO: handle exception
						fc.relogin();
						fc.entryDir(ffm.getFtpFileModel().getDir());
					}
					fc.setFileType(FTP.BINARY_FILE_TYPE);
					InputStream f = fc.downFile(ffm.getFtpFileModel().getFileName());

					byte[] data = new byte[defaultSize];
					int a = 0;

					while ((a = f.read(data)) > 0) {
						sc.write(data, 0, a);
					}
					f.close();
					fc.completePendingCommand();

					sc.write(TransmissionAction._end.toString());

					byte[] b = new byte[50];
					Thread.sleep(10);

					int read = sc.read(b);

					if (read > 0) {
						String s = new String(b, 0, read);
						if (s != null && s.equals("true")) {
							if (!isSave)
								fc.deleteFile(ffm.getFtpFileModel().getFileName());
						}
					}
				} else {
					return new SyncFile(ffm, "false");
				}
			} catch (Exception e) {
				// TODO: handle exception
				try {
					Runtime.getRuntime()
							.exec("logger -p local5.info ftp-client-send-file-error=ftpId:" + ffm.getFtpId()
									+ ",file dir:" + ffm.getFtpFileModel().getDir() + ",file name:"
									+ ffm.getFtpFileModel().getFileName() + ",file size:"
									+ ffm.getFtpFileModel().getFileSize());
				} catch (Exception e1) {
					// TODO: handle exception

				}
				try {
					sc.close();
				} catch (Exception e1) {
					// TODO: handle exception
					e.printStackTrace();
				}
				try {
					fc.logout();
				} catch (Exception e1) {
					// TODO: handle exception
					e.printStackTrace();
				}
			} finally {
				ftpSendClientTool.back(ftpSendClient);
			}
			return new SyncFile(ffm, "true");
		}

	}

	@Override
	public void fileSync(SyncFileMsg f, FtpSendClientTool ftpSendClientTool) {
		// TODO Auto-generated method stub
		SyncConfig ftpConfig = getFtpConfig();
		ExecutorCompletionService<SyncFile> ec = threadLocal.get().getExecutorService();
		FtpSendClient ftpSendClient = ftpSendClientTool.get();
		ec.submit(new FtpSyncCallable(ftpSendClientTool, ftpSendClient, f, ftpConfig.getDefaultSize(),
				TransmissionAction.sync_, threadLocal.get().isSave()));
	}

	@Override
	public int fileCheckAndSync(SyncFileMsg f, SocketClient copy) {
		// TODO Auto-generated method stub
		if (copy == null || (!copy.isConnected())) {
			try {
				copy.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			return -1;
		}
		byte[] b = new byte[1024];
		try {
			f.setPrefix(TransmissionAction.check_sync_);
			copy.write(f.toString());
			Thread.sleep(10);
			int read = copy.read(b);
			if (read > 0) {
				String string = new String(b, 0, read);
				if (!threadLocal.get().isSave()) {
					fileSync(f, threadLocal.get().getFtpSendClientTool());
					return 1;
				} else if (string != null && string.equals("false")) {
					fileSync(f, threadLocal.get().getFtpSendClientTool());
					return 1;
				} else if (string != null && string.equals("close")) {
					copy.close();
					try {
						Runtime.getRuntime()
								.exec("logger -p local5.info ftp-client-check-file-error=server no find ftpId:"
										+ f.getFtpId());
					} catch (Exception e1) {
						// TODO: handle exception

					}
					return -1;
				}
			} else {
				Thread.sleep(10);
				copy.read(b);
			}
		} catch (Exception e) {
			// TODO: handle exception
			// e.printStackTrace();
			try {
				copy.close();
			} catch (IOException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			return -1;
		}
		return 0;
	}

}
